package com.gitee.wsl.common.chart.sample.gauge

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.Pair
import com.gitee.wsl.android.ext.math.calcArcEndPointXY
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.sample.AbstractCirChart
import com.gitee.wsl.android.ui.ext.type.textWidth
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.add
import com.gitee.wsl.jvm.math.div
import com.gitee.wsl.jvm.math.mul
import com.gitee.wsl.jvm.math.sub


import timber.log.Timber


/**
 * @ClassName GaugeChart
 * @Description  刻度盘基类
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */

class GaugeChart:AbstractCirChart() {

    //刻度步长
     val tickSteps = 10.0

    //标签
     val labels = mutableListOf<String>()

    //刻度
     val tickPaint: Paint by lazy {
         Paint().apply {
            style = Paint.Style.FILL
            isAntiAlias = true
            color = Color.rgb(50, 149, 222)
            strokeWidth = 1f
        }
    }

    //指针
     val pointerAngle = 20f
     val pointerLinePaint: Paint by lazy {
         Paint().apply {
             style = Paint.Style.FILL
             isAntiAlias = true
             color = Color.BLACK
             strokeWidth = 3f
         }
     }
     val pointerCirclePaint: Paint by lazy {
         Paint().apply {
             style = Paint.Style.FILL
             isAntiAlias = true
             color = Color.BLACK
             strokeWidth = 8f
         }
     }

    //分区填充色(比如绿，黄，红),以使区域更清楚
     val partitionFillPaint: Paint by lazy {
        Paint().apply {
            style = Paint.Style.FILL
            isAntiAlias = true
        }
    }

    //环
     val dountPaint: Paint by lazy {
        Paint().apply {
            style = Paint.Style.STROKE
            color = Color.rgb(50, 149, 222)
            isAntiAlias = true
            strokeWidth = 2f
        }
    }

    //分区填充数据源(角色(0-180)，颜色)
     val partitionDataset: List<Pair<Float, Int>>? = null

    //180度
     val startAngle = 180

    override fun getType(): ChartEnum.ChartType {
        return ChartEnum.ChartType.GAUGE
    }

    /**
     * 绘制饼图中显示所占比例 的扇区
     * @param paintArc    画笔
     * @param cirX    x坐标
     * @param cirY    y坐标
     * @param radius    半径
     * @param offsetAngle    偏移角度
     * @param curretAngle    当前角度
     * @throws Exception    例外
     */
    protected fun drawPercent(
        canvas: Canvas, paintArc: Paint,
        cirX: Float,
        cirY: Float,
        radius: Float,
        offsetAngle: Float,
        curretAngle: Float
    ) {
            val arcLeft: Float = Math.sub(cirX, radius)
            val arcTop: Float = Math.sub(cirY, radius)
            val arcRight: Float = Math.add(cirX, radius)
            val arcBottom: Float = Math.add(cirY, radius)
            val arcRF0 = RectF(arcLeft, arcTop, arcRight, arcBottom)

            //在饼图中显示所占比例  
            canvas.drawArc(arcRF0, offsetAngle, curretAngle, true, paintArc)

    }

    private fun drawLabels(canvas: Canvas) {
        val stepsAngle = 180 / (labels.size - 1)
        val radius = getRadius()
        //float calcRadius = radius  + radius/10f;				
        // getRadius()
        val calcRadius = Math.add(radius, Math.div(radius, 10f))
        val cirX: Float = bodyViewport.centerX
        //float cirY = plotArea.getCenterY();
        val cirY = getCirY()
        labelPaint.textAlign = Paint.Align.CENTER
        for ((i, label) in labels.withIndex()) {
            when (i) //开头
            {
                0 -> {
                    canvas.drawText(
                        label,
                        cirX - calcRadius, cirY, this.labelPaint
                    )
                }
                labels.size - 1 -> { //结尾
                    canvas.drawText(
                        label,
                        cirX + calcRadius, cirY, this.labelPaint
                    )
                }
                else -> {
                    //计算百分比标签
                    val pointF= Math.calcArcEndPointXY(
                        cirX, cirY, calcRadius, 180f + i * stepsAngle
                    )
                    //标识
                    canvas.drawText(label, pointF.x, pointF.y, this.labelPaint)
                }
            }
        }
    }

    /**
     * 绘制刻度
     */
    private fun drawTicks(canvas: Canvas) {
        //步长角度		
        val fd = tickSteps
        val stepsAngle: Float = Math.div(180.0f, fd.toFloat())
        val cirX: Float = bodyViewport.centerX
        val cirY = getCirY() //plotArea.getCenterY();
        val tickRadius: Float = Math.mul(getRadius(), 0.9f)
        var i = 0
        while (i < tickSteps) {
            if (0 == i) {
                i++
                continue
            }
            //float Angle =  (float) (180d + i *stepsAngle) ;					
            val Angle = Math.add(180.0, (i * stepsAngle).toDouble()).toFloat()
            var pointF = Math.calcArcEndPointXY(cirX, cirY, getRadius(), Angle)
            val startX = pointF.x
            val startY = pointF.y
            pointF= Math.calcArcEndPointXY(cirX, cirY, tickRadius, Angle)
            canvas.drawLine(startX, startY, pointF.x, pointF.y, tickPaint)
            i++
        }
    }

    /**
     * 绘制指针
     */
    private fun drawPointerLine(canvas: Canvas) {
        val currentRadius: Float = Math.mul(getRadius(), 0.9f)
        val cirX: Float = bodyViewport.centerX
        val cirY = getCirY() //plotArea.getCenterY();
        if (pointerAngle.compareTo(180f) == 0 || pointerAngle.compareTo(180f) == 1) //爆表了
        {
            //Log.e(TAG,"爆表了 !!!");
            canvas.drawLine(cirX, cirY, cirX + currentRadius, cirY, pointerLinePaint)
        } else if (pointerAngle.compareTo(0.0f) == 0
            || pointerAngle.compareTo(0.0f) == -1
        ) {
            //Log.e(TAG,"负角度???!!!");
            canvas.drawLine(cirX, cirY, cirX - currentRadius, cirY, pointerLinePaint)
        } else {
            val calcAngle = Math.add(pointerAngle, startAngle.toFloat())
            val pointF= Math.calcArcEndPointXY(cirX, cirY, currentRadius, calcAngle)
            val endX = pointF.x
            var endY = pointF.y
            if (endY.compareTo(cirY) == 1) endY = cirY
            canvas.drawLine(cirX, cirY, endX, endY, pointerLinePaint)
        }
    }

    /**
     * 绘制指针底部的圆
     */
    private fun drawPinterCircle(canvas: Canvas) {
        val cirX: Float = bodyViewport.centerX
        val cirY = getCirY() //plotArea.getCenterY();
        canvas.drawCircle(cirX, cirY, Math.mul(getRadius(), 0.05f), pointerCirclePaint)
    }


    /**
     * 绘制内部颜色分区填充
     * @throws Exception
     */
    private fun drawPartitionFill(canvas: Canvas): Boolean {
        if (null == partitionDataset || partitionDataset.isEmpty()) {
           Timber.d("数据源为空.")
            return false
        }
        var totalAngle = 0.0f
        val newRadius: Float = Math.mul(getRadius(), 0.8f)
        val cy = getCirY()
        val rect: RectF = RectF()
        rect.left = Math.sub(bodyViewport.centerX, newRadius)
        rect.top = Math.sub(cy, newRadius)
        rect.right = Math.add(bodyViewport.centerX, newRadius)
        rect.bottom = Math.add(cy, newRadius)
        for (pr in partitionDataset) {
            val AngleValue = pr.first as Float
            val total = Math.add(totalAngle, AngleValue)
            if (AngleValue.compareTo(0.0f) < 0) {
               Timber.d("负角度???!!!")
            } else if (total.compareTo(180.0f) == 1
            ) //(totalAngle + AngleValue) > 180)
            {
               Timber.d("输入的角度总计大于180度")
                return false
            }
            partitionFillPaint.color = (pr.second as Int)
            canvas.drawArc(rect, Math.add(totalAngle, 180.0f), AngleValue, true, partitionFillPaint)
            totalAngle = Math.add(totalAngle, AngleValue)
        }
        return false
    }

    private fun getCirY(): Float {
        var cirY: Float = this.bottom
        if (this.isShowBorder) {
            cirY -= (borderWidth / 2).toFloat()
        }
        cirY -= Math.mul(getRadius(), 0.05f) //底圆
        return cirY
    }

    @JvmName("getRadius1")
    fun getRadius(): Float {
        //半圆， 宽应当是高的两倍
        var r: Float = width / 2f
        if (this.isShowBorder) {
            r -= borderWidth
        }

        //找第一和最后一个标签
        if (labels.size > 0) {
            val e = labels.size - 1
            val left = labelPaint.textWidth( labels[0])
            val right =  labelPaint.textWidth( labels[e])
            val spadding = left.coerceAtLeast(right)
            r = Math.sub(r, spadding)
            r = Math.sub(r, width / 2)
        }
        r -= Math.mul(r, 0.05f) //底圆
        return r
    }

    /**
     * 绘制环
     * @throws Exception
     */
    private fun drawDount(canvas: Canvas) {
        drawPercent(
            canvas, dountPaint, bodyViewport.centerX, getCirY(),  //plotArea.getCenterY(),
            getRadius(), 180f, 180f
        )
    }

    /**
     * 绘制图
     */
    protected fun renderPlot(canvas: Canvas) {
            //外环
            drawDount(canvas)
            //依角度画好刻度线
            // 计算出坐标点,从圆心到点间画线
            drawTicks(canvas)
            //画上用于标识分区的扇区
            drawPartitionFill(canvas)
            //画上外围标签
            drawLabels(canvas)
            //最后再画指针
            drawPointerLine(canvas)
            //画上指针尾部的白色圆心
            drawPinterCircle(canvas)
    }


    override fun renderBody(canvas: Canvas): Boolean {
        super.renderBody(canvas)

        //绘制图表
        renderPlot(canvas)

        return true
    }

}